﻿//using GoogleMobileAds.Api;
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using Object = UnityEngine.Object;

public static class CandyUtils
{




    public static bool IsDebugAds()
    {

        return RemoteSettings.GetBool("isDebugAds", true);
    }



    #region Random

    public static T RandomList<T>(List<T> list)
    {
        if (list.Count != 0)
        {
            int n = RandomInt(0, list.Count - 1);

            T child = list[n];
            return child;
        }
        return default(T);
    }

    public static T RandomListNotRepeat<T>(List<T> list, HashSet<int> set)
    {
        if (list.Count != 0)
        {
            int n = RandomIntNotRepeat(0, list.Count - 1, set);

            T child = list[n];
            return child;
        }
        return default(T);
    }
    public static T RandomListNotRepeat<T>(List<T> list, T repeatT)
    {
        if (list.Count != 0)
        {
            var index = list.IndexOf(repeatT);
            int n = RandomIntNotRepeat(0, list.Count - 1, new HashSet<int>() { index });

            T child = list[n];
            return child;
        }
        return default(T);
    }

    public static int RandomIntOPP(int min, int max)
    {
        int num = RandomInt(0, 1);

        if (num > 0)
        {
            return RandomInt(min, max);
        }
        else
        {
            return -RandomInt(min, max);
        }
    }

    private static bool IsExit(HashSet<int> set, int value)
    {
        if (!set.Contains(value))
        {
            set.Add(value);
            return false;
        }

        return true;
    }

    public static int RandomIntNotRepeat(int min, int max, HashSet<int> set)
    {
        int totalNum = Mathf.Max(min, max) - Mathf.Min(min, max) + 1;
        if (totalNum == set.Count)
        {
            set.Clear();
        }

        int num = RandomInt(min, max);
        while (IsExit(set, num))
        {
            num = RandomInt(min, max);
        }
        return num;
    }

    public static HashSet<int> RandomIntNotRepeat(int min, int max)
    {
        HashSet<int> list = new HashSet<int>();

        int totalNum = Mathf.Max(min, max) - Mathf.Min(min, max) + 1;
        for (int i = 0; i < totalNum; i++)
        {
            int num = RandomIntNotRepeat(min, max, list);
            list.Add(num);
        }

        return list;
    }

    public static bool Hit()
    {
        int hit = RandomInt(0, 1);
        if (hit == 1)
        {
            return true;
        }
        return false;
    }

    // 获取随机数
    public static int RandomInt(int min, int max)
    {
        System.Random rnd = new System.Random(GetRandomSeed());
        return rnd.Next(min, max + 1);
    }

    public static void Reshuffle<T>(List<T> listtemp)
    {
        //随机交换
        System.Random ram = new System.Random();
        int currentIndex;
        T tempValue;
        for (int i = 0; i < listtemp.Count; i++)
        {
            currentIndex = ram.Next(0, listtemp.Count - i);
            tempValue = listtemp[currentIndex];
            listtemp[currentIndex] = listtemp[listtemp.Count - 1 - i];
            listtemp[listtemp.Count - 1 - i] = tempValue;
        }
    }

    private static int GetRandomSeed()
    {
        byte[] bytes = new byte[4];
        System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
        rng.GetBytes(bytes);

        return BitConverter.ToInt32(bytes, 0);
    }

    #endregion




    #region Save

    public static bool SaveTexture(Texture2D texture, string toFileNameFullPath)
    {
        if (texture != null)
        {
            System.IO.File.WriteAllBytes(toFileNameFullPath, texture.EncodeToPNG());
            return true;
        }

        return false;
    }

    public static Texture2D GetTexture(string toFileNameFullPath)
    {
        if (System.IO.File.Exists(toFileNameFullPath))
        {
            byte[] data = System.IO.File.ReadAllBytes(toFileNameFullPath);
            Texture2D texture = new Texture2D(2, 2, TextureFormat.ARGB32, false);
            texture.LoadImage(data);

            return texture;
        }
        return null;
    }

    public static bool RemoveTexture(string toFileNameFullPath)
    {
        if (System.IO.File.Exists(toFileNameFullPath))
        {
            System.IO.File.Delete(toFileNameFullPath);
            return true;
        }
        return false;
    }

    public static bool RenameTexture(string fromFileNameFullPath, string toFileNameFullPath)
    {
        if (System.IO.File.Exists(fromFileNameFullPath))
        {
            System.IO.File.Move(fromFileNameFullPath, toFileNameFullPath);
            return true;
        }
        else
        {
            return false;
        }
    }
    public static Sprite GetSprite(string name)
    {
        Texture2D texture = GetTextureFrom(name);
        if (!texture)
        {
            return null;
        }

        Sprite spr = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));

        return spr;
    }

    public static bool SaveTextureToPersistent(ref Texture2D texture, string name)
    {
        return SaveTexture(texture, Application.persistentDataPath + "/" + name + ".png");
    }

    public static Texture2D GetTextureFrom(string name)
    {
        return GetTexture(Application.persistentDataPath + "/" + name + ".png");
    }

    public static bool RemoveTextureToPersistent(string name)
    {
        return RemoveTexture(Application.persistentDataPath + "/" + name + ".png");
    }

    public static bool RenameTexturePersistent(string fromName, string toName)
    {
        string fromfilePath = Application.persistentDataPath + "/" + fromName + ".png";
        string tofilePath = Application.persistentDataPath + "/" + toName + ".png";
        return RenameTexture(fromfilePath, tofilePath);
    }

    // 序列化 Do not use on MobieDevice

    //private XmlSaver xs = new XmlSaver();

    public static void SaveToXml(string filePath, object sourceObj)
    {
        string path = Application.persistentDataPath + "/" + filePath + ".xml";
        Debug.Log(path);

        if (!string.IsNullOrEmpty(path) && sourceObj != null)
        {
            using (StreamWriter writer = new StreamWriter(path))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(sourceObj.GetType());
                xmlSerializer.Serialize(writer, sourceObj);
            }
        }

        //string gameDataFile = Application.persistentDataPath + "/" + filePath + ".xml";
        //string dataString = xs.SerializeObject(sourceObj, sourceObj.GetType());
        //xs.CreateXML(gameDataFile, dataString);
    }

    public static object LoadFromXml(string filePath, Type type)
    {
        //string gameDataFile = Application.persistentDataPath + "/" + filePath + ".xml";
        //object result = null;

        //if (xs.hasFile(gameDataFile))
        //{
        //    string dataString = xs.LoadXML(gameDataFile);
        //    result = xs.DeserializeObject(dataString, type);
        //}

        string path = Application.persistentDataPath + "/" + filePath + ".xml";
        object result = null;

        if (File.Exists(path))
        {
            using (StreamReader reader = new StreamReader(path))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                result = xmlSerializer.Deserialize(reader);
            }
        }

        return result;
    }

    public static string Serializer(object obj)
    {
        MemoryStream Stream = new MemoryStream();

        XmlSerializer xml = new XmlSerializer(obj.GetType());
        xml.Serialize(Stream, obj);

        Stream.Position = 0;

        StreamReader sr = new StreamReader(Stream);
        string str = sr.ReadToEnd();

        sr.Dispose();
        Stream.Dispose();

        return str;
    }

    #endregion

    #region Collide

    #endregion




    #region Transfrom

    public static void ResetTransform(GameObject go)
    {
        var trans = go.transform;
        trans.localScale = Vector3.one;
        trans.localRotation = Quaternion.identity;
        trans.localPosition = Vector3.zero;
    }

    #endregion




    #region GameObjects

    public static T FindComponent<T>(GameObject go, string name) where T : Component
    {
        go = FindGameObjectByNameInAllChildren(go, name);
        return go == null ? null : go.GetComponent<T>();
    }

    public static T AddMissingComponent<T>(this GameObject go) where T : Component
    {
        T comp = go.GetComponent<T>();
        if (comp == null)
        {
            comp = go.AddComponent<T>();
        }
        return comp;
    }

    public static GameObject FindGameObjectByName(GameObject parent, string name)
    {
        if (parent == null)
        {
            return null;
        }

        Transform transform = parent.transform;
        foreach (Transform t in transform)
        {
            if (string.Equals(t.name, name))
            {
                return t.gameObject;
            }
        }

        return null;
    }

    public static GameObject FindGameObjectByNameInAllChildren(GameObject parent, string name)
    {
        if (parent == null)
        {
            return null;
        }

        GameObject g = FindGameObjectByName(parent, name);
        if (g != null)
        {
            return g;
        }

        Transform transform = parent.transform;
        foreach (Transform t in transform)
        {
            g = FindGameObjectByNameInAllChildren(t.gameObject, name);
            if (g != null)
            {
                return g;
            }
        }
        return null;
    }
    static Dictionary<string, Object> List = new Dictionary<string, Object>();

    public static GameObject InstantiatePrefab(string prefabFullpath)
    {
        if(List.ContainsKey(prefabFullpath))
           if(List[prefabFullpath]!=null)
            return GameObject.Instantiate(List[prefabFullpath]) as GameObject;
          else 
           return GameObject.Instantiate(Resources.Load(prefabFullpath)) as GameObject;
        else
        {
            List.Add(prefabFullpath,Resources.Load(prefabFullpath));
            return GameObject.Instantiate(List[prefabFullpath]) as GameObject;
        }
    }

    public static GameObject InstantiatePrefab(string prefabFullpath, GameObject parent)
    {
        return UnityEngine.Object.Instantiate(Resources.Load(prefabFullpath), parent.transform) as GameObject;
    }

    public static GameObject InstantiatePrefab(string prefabFullpath, Vector3 pos, Quaternion rotation, GameObject parent)
    {
        return UnityEngine.Object.Instantiate(Resources.Load(prefabFullpath), pos, rotation, parent.transform) as GameObject;
    }

    public static GameObject AddChild(GameObject parent, GameObject child, bool layerFollowParent = true)
    {
        if (layerFollowParent)
        {
            child.layer = parent.layer;
        }

        child.transform.parent = parent.transform;
        child.transform.localScale = Vector3.one;
        child.transform.localRotation = Quaternion.identity;
        child.transform.localPosition = Vector3.zero;
        return child;
    }


    //public static GameObject InstantiateFromPool(string prefabFullpath, GameObject parent)
    //{
    //    PoolManager.Instance.CreatePool(prefabFullpath)
    //}
    #endregion

    public static GameObject FindGameObject(string parent, string go)
    {
        GameObject parentGo = GameObject.Find(parent);
        return FindGameObject(parentGo, go);
    }

    public static GameObject FindGameObject(GameObject parentGo, string go)
    {
        if (parentGo)
        {
            return FindGameObjectByNameInAllChildren(parentGo, go);
        }
        else
        {
            return null;
        }

    }

    public static void DestoryAllChildren(GameObject parentGo)
    {
        foreach (Transform child in parentGo.transform)
        {
            UnityEngine.Object.Destroy(child.gameObject);
        }
    }

    public static void DisableAllChildren(GameObject parentGo)
    {
        foreach (Transform child in parentGo.transform)
        {
            child.gameObject.SetActive(false);
        }
    }

    /// <summary>
    /// 设置active,状态变更时,才切换
    /// </summary>
    /// <param name="gameObject"></param>
    /// <param name="isActive"></param>
    public static void SetActive(GameObject gameObject, bool isActive)
    {
        if(!gameObject)
        {
            return;
        }
        if (gameObject.activeSelf && !isActive)
        {
            gameObject.SetActive(false);
        }
        else if (!gameObject.activeSelf && isActive)
        {
            gameObject.SetActive(true);
        }
    }

    #region IAP

    public static void RemoveAds()
    {
        PlayerPrefs.SetInt("RemoveAds", 1);
    }

    public static bool IsRemoveAds()
    {
        return PlayerPrefs.GetInt("RemoveAds", 0) == 1;
    }

    public static bool IsUnlock(string iapId)
    {
        return PlayerPrefs.GetInt(iapId, 0) == 1;
    }

    #endregion



    #region Public.
    /// <summary>
    /// 系统分享
    /// </summary>
    public static void ShareMore(string text = null, string url = null, string imagePath = null)
    {
#if UNITY_EDITOR
        Debug.Log("ShareMore");
        return;
#endif


    }
    #endregion


    #region ScreenShoot

    public static Texture2D lastTakePhotoTexture;
    private static RenderTexture s_lastCSRender = null;
    public static Texture2D s_lastCSTexture = null;
    //private static string s_lastCSFromFileName = null;
    public static void TakePhoto()
    {
        int mask = ~(1 << LayerMask.NameToLayer("UI"));
        int storeMask = Camera.main.cullingMask;
        Camera.main.cullingMask = mask;
        if (lastTakePhotoTexture != null)
        {
            UnityEngine.Object.Destroy(lastTakePhotoTexture);
        }
        lastTakePhotoTexture = ScreenCapture.CaptureScreenshotAsTexture();
        Camera.main.cullingMask = storeMask;
        CandyUtils.SaveTextureToPersistent(ref lastTakePhotoTexture, "screenShot");
    }
    public static Texture2D CaptureScreen(Camera camera, bool isTransparent = false, int cullingMask = -1)
    {
        //s_lastCSFromFileName = null;

        // backup culling mask
        int oldCullingMask = camera.cullingMask;
        if (cullingMask != -1)
        {
            camera.cullingMask = cullingMask;
        }

        // create render
        if (s_lastCSRender == null)
        {
            s_lastCSRender = new RenderTexture(Screen.width, Screen.height, 24,
                                               RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
        }

        // create texture
        if (s_lastCSTexture != null && (s_lastCSTexture.width != Screen.width || s_lastCSTexture.height != Screen.height))
        {
            UnityEngine.Object.Destroy(s_lastCSTexture);
            s_lastCSTexture = null;
        }

        if (s_lastCSTexture == null)
        {
            s_lastCSTexture = new Texture2D(Screen.width, Screen.height, isTransparent ? TextureFormat.ARGB32 : TextureFormat.RGB24, false);
            s_lastCSTexture.wrapMode = TextureWrapMode.Clamp;
        }

        // do render MainCamera
        camera.targetTexture = s_lastCSRender;
        camera.Render();
        camera.targetTexture = null;

        // read to texture2d
        RenderTexture.active = s_lastCSRender;
        s_lastCSTexture.ReadPixels(new Rect(0, 0, s_lastCSRender.width, s_lastCSRender.height), 0, 0);
        s_lastCSTexture.Apply();
        RenderTexture.active = null;

        // restore culling mask
        if (cullingMask != -1)
        {
            camera.cullingMask = oldCullingMask;
        }

        return s_lastCSTexture;
    }
    public static Texture2D DoSnapshot()
    {
        return CaptureScreen(Camera.main, false, -1);
    }

    public static void AutoSetLabel(GameObject go)
    {
        if (go == null)
        {
            return;
        }
        var textLabels = go.GetComponentsInChildren<Text>(true);
        foreach (var textLbl in textLabels)
        {
            string name = textLbl.name;
            if (name.StartsWith("@"))
            {
                //var st = StringTemplate.Tem(name);
                //if (st != null)
                //{ 
                //    textLbl.text = st.text.Replace("/n", Environment.NewLine);
                //}
                //else
                //{
                //    Debug.LogWarning("The String Key " + name + " is missing");
                //}
            }
        }
    }

    //public static string GetLanguage()
    //{
    //    return MTUtils.GetLanguage();
    //}

    public static void SetLocalizSprite(SpriteRenderer sp)
    {
        // var name = sp.name;
        // if (GetLanguage()=="chinese")
        // {
        //     if (name.Contains("_cn"))
        //     {

        //     } else
        //     {
        //         sp.sprite.
        //     }
        // }


    }
    #endregion

    #region CanClick
    public static bool CanClick(float t = 0.5f)
    {
        return CanClick("_default_", t);
    }

    private static Dictionary<string, float> s_canClickLastTimeMap = new Dictionary<string, float>();
    public static bool CanClick(string key, float t = 0.5f)
    {
        float now = Time.realtimeSinceStartup;

        float ptime;
        if (!s_canClickLastTimeMap.TryGetValue(key, out ptime))
        {
            s_canClickLastTimeMap.Add(key, now);
            return true;
        }

        if (now - ptime > t)
        {
            s_canClickLastTimeMap[key] = now;
            return true;
        }

        return false;
    }
    #endregion

    #region Math

    public static Vector2 AngleToVector2(float angle)
    {
        return new Vector2(Mathf.Cos(Mathf.Deg2Rad * angle), Mathf.Sin(Mathf.Deg2Rad * angle)).normalized;
    }

    public static float Vector2ToAngle(Vector2 direction)
    {
        return Vector2.SignedAngle(direction, Vector2.right);
    }

    public static float AngleTo180Angle(float angle)
    {
        if(angle == float.MinValue)
        {
            return angle;
        }
        while(angle>180)
        {
            angle -= 360;
        }
        while(angle<-180)
        {
            angle += 360;
        }
        return angle;
    }


    #endregion


    #region  Position
    public static Vector3 WorldToUIPoint(Canvas canvas, Transform worldGo)
    {
        Vector3 v_v3 = Camera.main.WorldToScreenPoint(worldGo.position);
        Vector3 v_ui = canvas.worldCamera.ScreenToWorldPoint(v_v3);
        Vector3 v_new = new Vector3(v_ui.x, v_ui.y, canvas.GetComponent<RectTransform>().anchoredPosition3D.z);
        return v_new;
    }
    public static Vector3 WorldToUIPoint(Canvas canvas, Vector3 worldPosition)
    {
        Vector3 v_v3 = Camera.main.WorldToScreenPoint(worldPosition);
        Vector3 v_ui = canvas.worldCamera.ScreenToWorldPoint(v_v3);
        Vector3 v_new = new Vector3(v_ui.x, v_ui.y, canvas.GetComponent<RectTransform>().anchoredPosition3D.z);
        return v_new;
    }
    public static Vector3 ScreenPointToUIPoint(Canvas canvas,Vector3 screenPoint)
    {
        Vector3 v_ui = canvas.worldCamera.ScreenToWorldPoint(screenPoint);
        Vector3 v_new = new Vector3(v_ui.x, v_ui.y, canvas.GetComponent<RectTransform>().anchoredPosition3D.z);
        return v_new;
    }
    #endregion

    #region Taptic

    //public static void SuccessTaptic()
    //{
    //    Sequence seq = DOTween.Sequence();
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.2f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Medium);
    //    });
    //    seq.AppendInterval(0.2f);
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.2f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Medium);
    //    });
    //    seq.AppendInterval(0.2f);
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.2f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Heavy);
    //    });
    //}
    //public static void FailTaptic()
    //{
    //    Sequence seq = DOTween.Sequence();
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.2f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Heavy);
    //    });
    //    seq.AppendInterval(0.2f);
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.1f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Light);
    //    });
    //    seq.AppendInterval(0.2f);
    //    seq.AppendCallback(() =>
    //    {
    //        if (CanClick("Taptic", 0.1f)) GameApplication.Instance.TapticImpact(MTApplication.TapticImpactType.Light);
    //    });
    //}

    #endregion


    #region Delay Action
    public static Dictionary<int, Sequence> Actions = new Dictionary<int, Sequence>();
    public static int ActionId=-999;
    public static int DelayAction(Action action,float DelayTime)
    {
        Sequence delaySeq = DOTween.Sequence();
        delaySeq.AppendInterval(DelayTime);
        delaySeq.AppendCallback(()=> { action?.Invoke(); Actions.Remove(ActionId); });
        delaySeq.SetAutoKill(true);
        delaySeq.SetId(ActionId);
        Actions.Add(ActionId, delaySeq);
        return ActionId++;
    }

    public static void DesDelayAction(int ActionId)
    {
        Sequence delaySeq ;
        if (Actions.TryGetValue(ActionId, out delaySeq))
        {
            if (delaySeq.intId == ActionId)
            {
                delaySeq.Kill(true);
                Actions.Remove(ActionId);
            }
        }
    }

    #endregion
}
